import os
import json
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from docx import Document
from docx.shared import Inches
from PIL import Image
from datetime import datetime


class ConfigurableWordTemplateApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Word模板替换工具 - 可配置版")

        # 初始化变量
        self.template_path = tk.StringVar(value=self.get_default_template_path())
        self.output_path = tk.StringVar()
        self.output_filename = tk.StringVar(value="output.docx")
        self.config_path = tk.StringVar(value="config.json")
        self.text_placeholders = []
        self.image_placeholders = []

        # 加载配置
        self.load_config()

        # 创建界面
        self.create_widgets()

    # 新增方法：获取默认模板路径
    def get_default_template_path(self):
        default_path = "模板.docx"
        if os.path.exists(default_path):
            return os.path.abspath(default_path)
        return ""

    def load_config(self):
        """加载配置文件"""
        try:
            with open(self.config_path.get(), 'r', encoding='utf-8') as f:
                config = json.load(f)

                # 加载文本占位符
                self.text_placeholders = []
                for item in config.get("text_placeholders", []):
                    # 如果占位符是 {date}，设置默认值为今天的日期
                    default_value = datetime.today().strftime("%Y-%m-%d") if item.get(
                        "placeholder") == "{date}" else item.get("default", "")
                    self.text_placeholders.append({
                        "name": item["name"],
                        "placeholder": item["placeholder"],
                        "value": tk.StringVar(value=default_value),
                        "entry": None  # 稍后在GUI中创建
                    })

                # 加载图片占位符
                self.image_placeholders = []
                for item in config.get("image_placeholders", []):
                    self.image_placeholders.append({
                        "name": item["name"],
                        "placeholder": item["placeholder"],
                        "value": tk.StringVar(value=item.get("default", "")),
                        "entry": None,  # 稍后在GUI中创建
                        "browse_btn": None  # 浏览按钮
                    })

        except FileNotFoundError:
            messagebox.showerror("错误", f"配置文件 {self.config_path.get()} 未找到")
            # 使用默认配置
            self.text_placeholders = [
                {"name": f"占位符{i + 1}", "placeholder": f"{{placeholder_{i + 1}}}", "value": tk.StringVar(),
                 "entry": None}
                for i in range(10)
            ]
            self.image_placeholders = [
                {"name": f"图片{i + 1}", "placeholder": f"{{image_placeholder_{i + 1}}}", "value": tk.StringVar(),
                 "entry": None, "browse_btn": None}
                for i in range(5)
            ]
        except Exception as e:
            messagebox.showerror("错误", f"加载配置文件时出错:\n{str(e)}")
            # 使用默认配置
            self.text_placeholders = [
                {"name": f"占位符{i + 1}", "placeholder": f"{{placeholder_{i + 1}}}", "value": tk.StringVar(),
                 "entry": None}
                for i in range(10)
            ]
            self.image_placeholders = [
                {"name": f"图片{i + 1}", "placeholder": f"{{image_placeholder_{i + 1}}}", "value": tk.StringVar(),
                 "entry": None, "browse_btn": None}
                for i in range(5)
            ]

    def create_widgets(self):
        """创建GUI界面"""
        # 配置文件部分
        config_frame = ttk.LabelFrame(self.root, text="配置设置", padding=10)
        config_frame.grid(row=0, column=0, columnspan=3, sticky="ew", padx=5, pady=5)

        ttk.Label(config_frame, text="配置文件:").grid(row=0, column=0, sticky="w")
        ttk.Entry(config_frame, textvariable=self.config_path, width=40).grid(row=0, column=1, padx=5)
        ttk.Button(config_frame, text="浏览", command=self.browse_config).grid(row=0, column=2, padx=5)
        ttk.Button(config_frame, text="重新加载", command=self.reload_config).grid(row=0, column=3, padx=5)

        # 模板文件选择
        ttk.Label(self.root, text="Word模板文件:").grid(row=1, column=0, sticky="w", padx=5, pady=5)
        ttk.Entry(self.root, textvariable=self.template_path, width=40).grid(row=1, column=1, padx=5, pady=5)
        ttk.Button(self.root, text="浏览", command=self.browse_template).grid(row=1, column=2, padx=5, pady=5)

        # 文本替换部分
        ttk.Label(self.root, text="文本替换").grid(row=3, column=0, columnspan=3, sticky="w", padx=5, pady=10)

        for i, placeholder in enumerate(self.text_placeholders):
            frame = ttk.Frame(self.root)
            frame.grid(row=4 + i // 2, column=i % 2, padx=5, pady=5, sticky="ew")

            ttk.Label(frame, text=f"{placeholder['name']}:").pack(side="left")
            entry = ttk.Entry(frame, textvariable=placeholder["value"], width=30)
            entry.pack(side="left", padx=5)
            placeholder["entry"] = entry

        # 图片替换部分
        ttk.Label(self.root, text="图片替换").grid(row=4 + len(self.text_placeholders) // 2 + 1, column=0, columnspan=3,
                                                   sticky="w", padx=5, pady=10)

        for i, placeholder in enumerate(self.image_placeholders):
            frame = ttk.Frame(self.root)
            frame.grid(row=5 + len(self.text_placeholders) // 2 + i // 2, column=i % 2, padx=5, pady=5, sticky="ew")

            ttk.Label(frame, text=f"{placeholder['name']}:").pack(side="left")
            entry = ttk.Entry(frame, textvariable=placeholder["value"], width=20)
            entry.pack(side="left", padx=5)
            placeholder["entry"] = entry

            btn = ttk.Button(frame, text="浏览", command=lambda p=placeholder: self.browse_image(p))
            btn.pack(side="left", padx=5)
            placeholder["browse_btn"] = btn

        # 处理按钮
        ttk.Button(self.root, text="生成Word文档", command=self.process_document).grid(
            row=6 + len(self.text_placeholders) // 2 + len(self.image_placeholders) // 2,
            column=0, columnspan=3, pady=20
        )

    # 新增配置文件浏览方法
    def browse_config(self):
        initial_dir = os.path.dirname(self.config_path.get()) if self.config_path.get() else "."
        filepath = filedialog.askopenfilename(
            title="选择配置文件",
            initialdir=initial_dir,
            filetypes=[("JSON文件", "*.json")],
            defaultextension=".json"
        )
        if filepath:
            self.config_path.set(filepath)
            self.reload_config()


    # 修改browse_template方法支持默认路径
    def browse_template(self):
        initial_dir = os.path.dirname(self.template_path.get()) if self.template_path.get() else "."
        initial_file = "模板.docx" if not self.template_path.get() else os.path.basename(self.template_path.get())

        filepath = filedialog.askopenfilename(
            title="选择Word模板",
            initialdir=initial_dir,
            initialfile=initial_file,
            filetypes=[("Word文档", "*.docx")]
        )
        if filepath:
            self.template_path.set(filepath)
            # 自动设置输出路径为同目录
            output_dir = os.path.dirname(filepath)
            self.output_path.set(output_dir)
            filename = os.path.splitext(os.path.basename(filepath))[0] + "_output.docx"
            self.output_filename.set(filename)


    # 修改reload_config方法增强错误处理
    def reload_config(self):
        """重新加载配置文件并刷新界面"""
        try:
            # 备份当前值用于恢复
            prev_text_values = {p["placeholder"]: p["value"].get() for p in self.text_placeholders}
            prev_image_values = {p["placeholder"]: p["value"].get() for p in self.image_placeholders}

            self.load_config()

            # 恢复用户已输入的值
            for p in self.text_placeholders:
                if p["placeholder"] in prev_text_values:
                    p["value"].set(prev_text_values[p["placeholder"]])

            for p in self.image_placeholders:
                if p["placeholder"] in prev_image_values:
                    p["value"].set(prev_image_values[p["placeholder"]])

            # 清除现有界面元素（从文本和图片部分开始）
            for widget in self.root.grid_slaves():
                if widget.grid_info()["row"] >= 4:  # 假设前3行是配置和文件选择
                    widget.grid_forget()

            # 重新创建界面
            self.create_widgets()

        except Exception as e:
            messagebox.showerror("配置加载错误", f"无法加载配置文件:\n{str(e)}")
            # 回退到默认配置
            self.config_path.set("config.json")

    def browse_template(self):
        filepath = filedialog.askopenfilename(filetypes=[("Word文档", "*.docx")])
        if filepath:
            self.template_path.set(filepath)
            # 自动设置输出路径为同目录
            output_dir = os.path.dirname(filepath)
            self.output_path.set(output_dir)
            filename = os.path.splitext(os.path.basename(filepath))[0] + "_output.docx"
            self.output_filename.set(filename)

    def browse_output(self):
        initial_dir = os.path.expanduser("~")
        if self.template_path.get():
            initial_dir = os.path.dirname(self.template_path.get())

        filepath = filedialog.asksaveasfilename(
            defaultextension=".docx",
            filetypes=[("Word文档", "*.docx")],
            initialdir=initial_dir,
            initialfile=self.output_filename.get()
        )
        if filepath:
            self.output_filename.set(os.path.basename(filepath))
            self.output_path.set(os.path.dirname(filepath))

    def browse_image(self, placeholder):
        filepath = filedialog.askopenfilename(filetypes=[("图片文件", "*.jpg;*.jpeg;*.png;*.bmp")])
        if filepath:
            placeholder["value"].set(filepath)

    def process_document(self):
        if not self.template_path.get():
            messagebox.showerror("错误", "请先选择Word模板文件")
            return

        if not self.output_filename.get():
            messagebox.showerror("错误", "请设置输出文件名")
            return

        try:
            # 加载模板文档
            doc = Document(self.template_path.get())

            # 处理文本替换
            text_replacements = {}
            for placeholder in self.text_placeholders:
                if placeholder["value"].get():
                    text_replacements[placeholder["placeholder"]] = placeholder["value"].get()

            # 获取 project_name 的值
            project_name_value = text_replacements.get("{project_name}", "默认值或空字符串")
            print(f"Project Name: {project_name_value}")  # 打印到控制台，或者你可以进行其他操作
            file_id = text_replacements.get("{file_id}", "默认值或空字符串")
            print(f"file id: {file_id}")  # 打印到控制台，或者你可以进行其他操作

            file_name = project_name_value+"_"+file_id

            # 处理图片替换
            image_replacements = {}
            for placeholder in self.image_placeholders:
                if placeholder["value"].get() and os.path.exists(placeholder["value"].get()):
                    image_replacements[placeholder["placeholder"]] = placeholder["value"].get()

            # 替换文档中的内容
            self.replace_in_doc(doc, text_replacements, image_replacements)

            # 保存文档
            output_path = os.path.join(self.output_path.get(), self.output_filename.get())
            doc_name = f"{file_name}.docx"
            doc.save(doc_name)

            # 保存数据到JSON文件
            self.save_data_to_json(output_path, file_name)

            messagebox.showinfo("成功", f"文档已成功生成到:\n{doc_name}")
        except Exception as e:
            messagebox.showerror("错误", f"处理文档时出错:\n{str(e)}")

    def replace_in_doc(self, doc, text_replacements, image_replacements):
        # 替换段落中的文本
        for para in doc.paragraphs:
            self.replace_in_paragraph(para, text_replacements, image_replacements)

        # 替换表格中的文本
        for table in doc.tables:
            for row in table.rows:
                for cell in row.cells:
                    for paragraph in cell.paragraphs:
                        self.replace_in_paragraph(paragraph, text_replacements, image_replacements)

    def replace_in_paragraph(self, paragraph, text_replacements, image_replacements):
        for key, value in text_replacements.items():
            if key in paragraph.text:
                paragraph.text = paragraph.text.replace(key, value)

        for key, image_path in image_replacements.items():
            if key in paragraph.text:
                if not os.path.exists(image_path):
                    print(f"错误：图片 {image_path} 不存在！")
                    continue

                # 将 BMP 转换为 PNG 避免兼容性问题
                if image_path.lower().endswith('.bmp'):
                    try:
                        img = Image.open(image_path).convert("RGB")
                        png_path = "temp.png"
                        img.save(png_path)
                        image_path = png_path
                    except Exception as e:
                        print(f"转换图片失败: {e}")
                        continue

                # 直接替换占位符为图片
                paragraph.text = paragraph.text.replace(key, "")
                run = paragraph.add_run()
                run.add_picture(image_path, width=Inches(2))  # 按需调整尺寸

    def get_page_size(self, document):
        # 此处为示例代码，具体实现可能需要根据实际情况调整
        # 假设获取第一个section的页面大小作为页面大小
        sections = document.sections
        if sections:
            page_width = sections[0].page_width
            page_height = sections[0].page_height
            return page_width, page_height
        return None, None  # 如果没有section，则返回None

    def save_data_to_json(self, doc_path, name):
        """保存当前数据到JSON文件(保持与config.json相同结构)"""
        try:
            # 准备数据（完全匹配config.json结构）
            data = {
                "text_placeholders": [
                    {
                        "name": p["name"],
                        "placeholder": p["placeholder"],
                        # 保留原始默认值，仅当用户输入时更新
                        "default": p["value"].get() or p.get("original_default", "")
                    } for p in self.text_placeholders
                ],
                "image_placeholders": [
                    {
                        "name": p["name"],
                        "placeholder": p["placeholder"],
                        # 保留原始默认值，仅当用户输入时更新
                        "default": p["value"].get() or p.get("original_default", "")
                    } for p in self.image_placeholders
                ]
            }

            # 生成JSON文件名
            json_filename = f"{name}.json"
            json_path = os.path.join(self.output_path.get(), json_filename)

            # 保存到JSON文件（保持缩进和格式）
            with open(json_path, 'w', encoding='utf-8') as f:
                json.dump(data, f,
                          ensure_ascii=False,
                          indent=4,
                          separators=(',', ': '))

            messagebox.showinfo("成功", f"数据已保存到:\n{json_path}")
        except Exception as e:
            messagebox.showerror("错误", f"保存数据到JSON文件时出错:\n{str(e)}")

if __name__ == "__main__":
    root = tk.Tk()
    app = ConfigurableWordTemplateApp(root)
    root.mainloop()